| 나의 플랫폼/안드로이드 2011/09/06 13:48 글로우 효과를 내거나 이미지에 발광 효과를 줄려고 할 때 사용하면 괜찮을 것 같아서 이렇게 글을 남깁니다. Opengl es 같은 경우 자체적으로 diffuse(범위) 빛 효과 값을 이용하여 글로우 효과를 표현하기도 하는 것 같은데요.. 만약 랜더링 되지 않은 그냥 bitmap 파일을 글로우 효과를 낼려면.. 어쩔수 없이 bitmap 자체를 변경 시켜줘야 한다는 게 몇일 간 조사한 저의 결과 였습니다. bitmap변경은 다음과 같이 이용하였습니다. // bitmap 소스를 받아온다. Bitmap tmpbitmap = BitmapFactory.decodeStream(mContext.getResources().openRawResource(R.raw.lightmap)); tmpbitmap = Bitmap.createScaledBitmap(tmpbitmap, 256, 256, true); Paint paint = new Paint();
int textureIndex = 0;
// 50개의 텍스처를 초기화 했습니다. for(float contrast = 0.0f ; textureIndex < 50 ; contrast += 0.1f,textureIndex++){ // 컬러 매트릭스 생성 ColorMatrix cm = new ColorMatrix(); // 컬러 캐트릭스를 적용 시킨 비트맵을 그릴 팔레트Bitmap Bitmap paletBmp = Bitmap.createBitmap(tmpbitmap.getWidth(), tmpbitmap.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(paletBmp); // contrast값이 높아 질수록 밝아진다. ( 글로우 효과일 경우 보이는 부분이 줄어드는 효과를 볼 수 있죠.) setContrastScaleOnly(cm, contrast); // 컬러 필터로 적용 paint.setColorFilter(new ColorMatrixColorFilter(cm)); canvas.save(); canvas.drawBitmap(tmpbitmap, 0,0, paint); canvas.restore(); mLightMapTexId[textureIndex] = loadTexture(paletBmp); } tmpbitmap.recycle(); tmpbitmap = null; 아마 글로우 효과를 내는데 제가 잘못 생각할 수도 있을 것 같네요.. 혹시 다른 의견이나~~ 괜찮은 생각 있으신 분~~~ 특히 Opengl es 2.0을 이용하는 방법이면 더욱 환영입니다.^^ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 출처: http://gogorchg.tistory.com/entry/Android-Opengl-es-Blur%ED%9A%A8%EA%B3%BC 아직 실험해보지는 않았다.
이것도 역시 Bitmap의 컬러값을 이용하여,변경하는 함수이다.
function BlurHorizontal (source, dest, radius) {
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
total = 0
for (kx = -radius; kx <= radius; ++kx)
total += source(x + kx, y)
dest(x, y) = total / (radius * 2 + 1)
}
}
}
function BlurVertical (source, dest, radius) {
for (x = 0; x < width; ++x) {
for (y = 0; y < height; ++y) {
total = 0
for (ky = -radius; ky <= radius; ++ky)
total += source(x, y + ky)
dest(x, y) = total / (radius * 2 + 1)
}
}
}
function Blur (source, dest, radius) {
BlurHorizontal(source, temp, radius)
BlurVertical(temp, dest, radius)
} 출처 : http://www.blackpawn.com/texts/blur/default.html
중요한 건 , 모든 연산이 CPU에서 하기 때문에. 매번 블러를 적용시킬려고 하면, 속도가 현저하게 저하되는 것을 느낄 수 있을 것 같다.
먼가 Opengl es 내적으로 GPU를 이용하는 방법을 빨리 찾아야 할 것 같다.
어렵다 정말...^^;;;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 출처: http://gogorchg.tistory.com/entry/Android-Opengl-es-20-Blur-%ED%9A%A8%EA%B3%BC 드뎌!!!! Blur효과를 냈습니다. 아마 이런 것 가지고 하시는 분들 계시겠지만, 저한테는 너무 기분 좋은 일이네요.^^
이 효과를 내고 싶어도... 낼 수가 없었던 지금까지의 고생이 오늘 해결 되었네요.
Opengl es 2.0으로 했구요. FrameShader 소스 부분의 컬러 값을 변경하면 됩니다.
String fShaderStr = "precision mediump float; \n" + "varying vec2 v_texCoord; \n" + // 이건 texture index 배열이죠. DrawElement에서 사용 "uniform sampler2D s_lightMap; \n" + // 이미지 텍스쳐 입니다. "uniform float u_blurAmount; \n" + // Blur을 먹이기 위해 Object간의 간격을 조절 "uniform int u_blurFlag; \n" + // 테스트를 위해 Blur 먹인 것과 아닌 것을 구분하는 Flag "void main() \n" + "{ \n" + " \n" + " vec4 lightColor; \n" + " \n" + " highp vec4 color = vec4(0,0,0,1); \n" + // 색깔을 받을 변수 // Blur를 가우스 공식에 의해 변경을 시켜주는 거지요. " if ( u_blurFlag == "+ENABLE_BLUR+"){ \n " + " highp vec2 gaussFilter[7]; \n" + " gaussFilter[0] = vec2(-3.0, 0.015625); \n" + " gaussFilter[1] = vec2(-2.0, 0.09375); \n" + " gaussFilter[2] = vec2(-1.0, 0.234375); \n" + " gaussFilter[3] = vec2(0.0, 0.3125); \n" + " gaussFilter[4] = vec2(1.0, 0.234375); \n" + " gaussFilter[5] = vec2(2.0, 0.09375); \n" + " gaussFilter[6] = vec2(3.0, 0.015625); \n" + " \n" + " highp float blurSize = u_blurAmount * 1.0; \n" + " \n" + " for( int i = 0; i < 7; i++ ) \n" + " color += texture2D( s_lightMap, vec2( v_texCoord.x+gaussFilter[i].x*blurSize, v_texCoord.y+gaussFilter[i].x*blurSize ) )*gaussFilter[i].y; \n" + " }else{ \n " + " color = texture2D( s_lightMap, v_texCoord ); \n" + " } \n" + " gl_FragColor = color ; \n" + "} \n"; 결과 화면:
위 쪽은 기본 이미지. 밑 쪽은 Blur 값을 넣은 이미지 입니다.
blurAmount를 0.01f로 줬을 때 나오는 결과구요.
더 주게 되면 Blur Object가 더욱 벌어져서 이상하게 보여버립니다. 이렇게요^^
왠지 오늘 너무 행복한 하루 네요~~^^
더 궁금한 거 있으시면 댓글 달아주세요 ㅎ
모두 추운 날씨 몸 조심하시고 즐코딩하세요~ ㅎ
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 출처: http://gogorchg.tistory.com/entry/Android-Opengl-es-20-glDrawArrays-%EC%99%80-glDrawElements-%EC%82%AC%EC%9A%A9%EB%B2%95 여러 소스를 보다 보면, glDrawArrays를 사용하거나, glDrawElements를 사용하기도 합니다.
그래서, 저 같은 경우는 이해하기 쉬운 glDrawArrays를 많이 사용했는데요.
// Vertex 배열을 만듬. private final float[] mVerticesData = { 0.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.0f, };
// Vertex Buffer에 포인터를 설정한다. GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, mVertices); // Vertex 속성을 허용한다. GLES20.glEnableVertexAttribArray(0); // Vertex의 포인터 갯수 만큼만 그린다. ( 0부터 18 )
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mVerticesData.length/3);
이렇게 Vertex만 잡아주면 쉽게 그릴 수 있는게 glDrawArrays이구요.
만약, 한 구역 내에서 여러 모양의 형태로 그리고 싶을 경우가 있을 때 , glDrawElements를 사용하는데요. 이 때 필요한 것이 Indices 배열입니다.
// Vertex 배열을 만듬. private final float[] mVerticesData = { 0.0f, 0.0f, 0.0f, // Vertex 0 -0.5f, 0.5f, 0.0f,// Vertex 1 0.5f, 0.5f, 0.0f, // Vertex 2 1.0f, 0.0f, 0.0f, // Vertex 3 0.5f, -0.5f, 0.0f,// Vertex 4 -0.5f, -0.5f, 0.0f,// Vertex 5 -1.0f, 0.0f, 0.0f,// Vertex 6 };
// Indice 배열을 만듬. private final short[] mIndicesData = { 0,2,1, // 삼각형 1 0,3,2,// 삼각형 2 0,4,3,// 삼각형 3 0,5,4,// 삼각형 4 0,6,5,// 삼각형 5 0,1,6,// 삼각형 6 };
// Vertex Buffer에 포인터를 설정한다. GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, mVertices); // Vertex 속성을 허용한다. GLES20.glEnableVertexAttribArray(0); // Indices 갯수만큼 설정.
GLES20.glDrawElements(GLES20.GL_TRIANGLE_FAN, mIndicesData.length, GLES20.GL_UNSIGNED_SHORT, mIndices); Vertex의 위치 를 보여드린 그림입니다. 각각 안에 삼각형이 6개가 그려지죠. 3각형을 그릴 포인트를 Indices 배열에 지정한 것입니다.
이 그림의 주소따라 mIndicesData 안에 값들 대로 그려보십시요.
아~~~ 하실 껍니다.^^
참고> glDrawElements를 할 경우, 여러 Object를 연결 시키고자 할때, Vertex는 많아도 indices로 연결을 시켜주면 되니 사용하기 편하다고 하네요..^^
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
출처: http://gogorchg.tistory.com/entry/Android-Opengl-es-20-VBOVertexArray-Buffer-Object-%EA%B4%80%EB%A0%A8%ED%95%B4%EC%84%9C
[Android Opengl es 2.0 ] VBO(VertexArray Buffer Object ) 관련해서
이번에 이해하게된 함수는
glGenBuffers, glBindBuffer,glBufferData 이 세 함수입니다.
이 함수에는 다음과 같은 코드로 Vertex 배열을 Opengl Buffer에 저장을 시켜서 Handle Number를 이용하여 사용을 하는데요.
// Buffer 생성 공간을 2군데 만든다. GLES20.glGenBuffers(2, vObjId); // Buffer 공간에서 첫번째와 연결
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vObjId.get(0)); // 연결된 첫번째 공간에 Static형태로 Vertex데이터를 저장 한다. GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mVerticesData.length * 4, mVertices, GLES20.GL_STATIC_DRAW); // 한 번 읽을 때마다 , float 4바이트를 3개씩 읽게 된다. ( ex> 0.0f,0.0f,0.0f ) GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, mVertices); // 속성 적용을 허용한다. GLES20.glEnableVertexAttribArray(0);
전 코드를 만들면서 생각에 큰 오류가 있었습니다.
바로 위 glGenBuffers라는 함수는 여러 Object에 대한 형태를 지정해 놓으면, Handle Number를 통하여 Object 모양을 바꿀 수 있을 줄 알았습니다.
하지만!!!!! glGenBuffers는 한 Object에 대한 여러 Attribute을 지정하는 것이었습니다.
즉, 한 Object에 한해서 밖에 생성이 안된다는 이야기입니다.
구글링을 해본 결과 얻은 결론은 Opengl es 버전이 아닌, 또는 안드로이드가 아니고 iOS내에 Opengl es 버전에는
glGenVertexArrays ( Opengl ) glGenVertexArraysOES ( iOS Opengl )
위 함수를 통하여 여러 Object를 Buffer에 지정할 수가 있는 것 같습니다.
우선, 제가 테스트해 본 결과로는 안드로이드에서 Buffer 여러 Object를 지정해 놓는 것은 힘들어 보이네요...
혹시 이 의견에 반발이 있으신 분은 주저 말고 댓글 달아주세요!!!
이게 100% 맞다고 할 수 없지 않습니까??^^
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 출처: http://gogorchg.tistory.com/entry/Android-Opengl-es-20-Vertex%EB%B0%B0%EC%97%B4%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-%EA%B0%84%EB%8B%A8%ED%95%9C-%EB%8F%84%ED%98%95-%EB%A7%8C%EB%93%A4%EA%B8%B0
안녕하세요.
이번엔 Vertex배열을 이용하여 제가 그린 그림을 보여드릴려고 합니다.
private final float[] mVerticesData = { 0.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.0f, }; 위와 같이 하게 되면 정육각형이 구해집니다.
먼저 결과 화면을 보여드리겠습니다.
Vertex로직은 다음과 같습니다.
public void onTouchEvent(MotionEvent event){ switch(event.getAction()){ case MotionEvent.ACTION_UP: if(drawType == GLES20.GL_TRIANGLES){ drawType = GLES20.GL_LINE_LOOP; }else{ drawType = GLES20.GL_TRIANGLES; } break; } } 그릴 때 마다 drawType을 변형 시켜서, Touch를 할 경우에 선일 경우에는 꽉 채우는 형태로, 꽉 채워져 있으면 선으로 그려보았습니다.
중요한 부분이 vertex의 순서를 잘못 하면 다음과 같은 결과가 날 수 있다는 것이지요.
GL_LINE_LOOP일 경우는 저희가 예전 놀이로 많이 했던, 연필을 때지 않고 선 그리기 형태로 선을 계속 그린다고 생각하시면 됩니다.
이렇게 Vertex를 공책이나 연습장에 생각해서 그려보신 후, 이제 VertexShader에 적용을 시켜야하는데요.
[ mVerticesBuffer가 사용되기 전에 적용] mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4) .order(ByteOrder.nativeOrder()).asFloatBuffer(); mVertices.put(mVerticesData).position(0);
[ Drawing 하는 함수에서]
// Vertex 값은 시작이 0이요, 3단위씩 끊어져 있소, 값은 Float형태요. // Float일 경우 false로 하지만, 만약 다른 데이터 형식일 때 true로 하면 normalize가 된다고 책있네요. // 3단위로 읽고, 0만큼 건너 뛰겠소. (나중에 Vertex배열에 여러가지를 겸해서 설정할 수도 있습니다.) // mVertices라는 ByteBuffer를 가지고 그리시요. GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, mVertices); GLES20.glEnableVertexAttribArray(0);
// 배열형태를 그립니다. // 총 배열의 Column 수는 18개 입니다. // 3단위씩 18개로 되어있죠. GLES20.glDrawArrays(drawType, 0, 18); 이렇게 간단하게 육각형을 그리는 연습을 해보았습니다. 이제 먼가 움직여도 보고 이것 저것 해볼려고 합니다.
Opengl es 1.0은 해봤는데.
먼가 2.0에서는 개발자에게 대한 자유도가 더 올라간 듯한 느낌도 들고, 이해하기가 더 복잡해 진것 같기도 하고..
아무튼!!! 공부해서 이해가 될 때 마다 글을 남겨둘까 합니다.
이 글이 많은 사람들에게 도움이 되면 좋겠습니다.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 출처: http://gogorchg.tistory.com/entry/Android-Opengl%EC%97%90%EC%84%9C-glDrawElements%ED%95%A8%EC%88%98%EB%A1%9C-%EA%B7%B8%EB%A6%B4-%EB%96%84-%EC%A3%BC%EC%9D%98%EC%A0%90
전 glDrawArray함수를 많이 사용하는데요.
폴라곤을 이용하여 텍스처를 입힐 때에는 glDrawElements함수를 사용하는 게 훨 편하고
속도면에서도 낫더라구요.
그런데 기존에 사용했던 glDrawArray함수와 glDrawElements함수를 사용할 때
준비해야할 점들이 다릅니다.
glDrawArray함수는 vertex 좌표만 있어도 표현이 가능하죠. ( 다른 Normal등 부수적인 것을 제외 )
하지만, glDrawElements함수에서는 vertex만큼 중요한 좌표가 두가지가 있죠.
바로!!! vertex포인터를 하게 될 좌표와 텍스처 포인터를 할 좌표!!
이 두가지를 확실하게 해주지 않으면 죽을 때까지 원하는 모양을 보실수 없으십니다.
먼저 , 텍스처 포인터를 할 때
위와 같이 두 포인터가 합쳐서 1을 표현해야만 합니다. 저 윗 그림을 배열로 표시하면 {
0.0 , 0.0 0.5 , 0.0 1.0 , 0.0 0.0 , 0.5 0.5 , 0.5 1.0 , 0.5 0.0 , 1.0 0.5 , 1.0 1.0 , 1.0 }
함수는 다음과 같습니다. 참고하세요.^^ : Java에서 테스트 한 거라 ㅎㅎ
private static void texturePoint(){ int i = 0; float delta_x = 1.0f / (float)(3-1); float delta_y = 1.0f / (float)(3-1); for (int y = 0; y < 3; y++) for (int x = 0; x < 3; x++) { System.out.println((float)x * delta_x + " , " + (float)y * delta_y); i += 2; } }
그 다음은 Vertex포인트 입니다.
똑같은 위 그림을 표현하면 배열이 다음과 같구요.
0 , 1 , 4 , 0 , 3 , 4 1 , 2 , 5 , 1 , 4 , 5 3 , 4 , 7, 3 , 6 , 7 4 , 5 , 8, 4 , 7 , 8
소스는 다음과 같습니다.
private static void vertexPoint(){ int i=0; for(int y=0;y<(3-1);y++){ for(int x=0;x< (3-1) ; x++){ int n = (y*3)+x; System.out.println((byte)n + " , " + (byte)(n+1) + " , " + (byte)(n+1+3)); System.out.println((byte)n + " , " + (byte)(n+1+3-1) + " , " + (byte)(n+1+3)); i+=6; } } } 저두 이걸로 조금 씩 텍스처의 개념이 이해가 되어 가고, DrawElements를 사용하는데 자신감이 생겼네요^^
어려움을 직면했을 때 포기말고 끝까지 해봅시다.!!!
도움이 되었으면 좋겠네요.. 화이팅!!
아!!! 지금 숫자 3은 가로 세로의 포인트 갯수가 각각 3개인 것입니다.^^ |